package simple.utils.concurrent;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * Created with IntelliJ IDEA.
 * User: rehak
 * Date: 8/20/13
 * Time: 10:32 AM
 * To change this template use File | Settings | File Templates.
 */
public class ConcurrentProperties<E> implements Iterable<Map.Entry<String, E>> {

    private final ConcurrentMap<String, List<E>> map = new ConcurrentHashMap<>();

    public ConcurrentProperties() {

    }

    /**
     * Removes everything
     */
    public void empty() {
        map.clear();
    }

    public Set<String> getPropNames() {
        return new HashSet<>(map.keySet());
    }

    public E get(String name) {
        List<E> l = getValues(name);
        if (l.size() > 0) {
            return l.get(0);
        } else {
            return null;
        }
    }

    public List<E> getValues(String name) {
        List<E> l = map.get(name);
        if (l != null) {
            return l;
        } else {
            return new ArrayList<E>();
        }
    }

    public void set(String name, E value) {
        List<E> l = new CopyOnWriteArrayList<>();
        if (value != null) {
            l.add(value);
        }
        map.put(name, l);
    }

    public void add(String name, E value) {
        List<E> list = map.get(name);
        if (list == null) {
            List<E> nl = new CopyOnWriteArrayList<>();
            list = map.putIfAbsent(name, nl);
            if (list == null) {
                list = nl;
            }
        }
        list.add(value);
    }

    public ConcurrentMap<String, List<E>> getBackingMap() {
        return map;
    }

    @Override
    public Iterator<Map.Entry<String, E>> iterator() {
        List<Map.Entry<String, E>> vals = new ArrayList<>();
        for (Map.Entry<String, List<E>> e : map.entrySet()) {
            final String key = e.getKey();
            for (final E value : e.getValue()) {
                vals.add(new Map.Entry<String, E>() {
                    @Override
                    public String getKey() {
                        return key;
                    }

                    @Override
                    public E getValue() {
                        return value;
                    }

                    @Override
                    public E setValue(E value) {
                        throw new UnsupportedOperationException("Not supported!");
                    }

                    @Override
                    public boolean equals(Object o) {
                        if (o instanceof Map.Entry) {
                            Map.Entry e = (Map.Entry) o;
                            return e.getKey().equals(getKey()) && e.getValue().equals(getValue());
                        }
                        return false;
                    }

                    @Override
                    public int hashCode() {
                        return getKey().hashCode();
                    }
                });
            }
        }
        return vals.iterator();
    }
}
